package com.link;

import com.link.util.SpringUtil;
import com.netflix.discovery.DiscoveryClient;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.threads.ThreadPoolExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.config.server.EnableConfigServer;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.ContextClosedEvent;

import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

@SpringBootApplication
@EnableConfigServer
@EnableDiscoveryClient
@RefreshScope
public class ConfigApplication {

    private static final Logger logger = LoggerFactory.getLogger(ConfigApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(ConfigApplication.class, args);
    }


    /**
     * 将自定义Tomcat连接器声明为bean，当应用产生关闭事件时才会回调对应得方法
     * @author 郭闪
     * @date 2019/12/10
     */
    @Bean
    public GracefulShutdown gracefulShutdown() {
        return new GracefulShutdown();
    }

  /**
   *将自定义webServer工程声明为bean。
   * @author 郭闪
   * @date 2019/12/10
   */
    @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        tomcat.addConnectorCustomizers(gracefulShutdown());
        return tomcat;
    }

    /**
     * 自定义Tomcat 连接器；监听应用关闭事件，在应用关闭时将应用从eureka下线，并使线程sleep 5秒钟，然后关闭应用
     * @author 郭闪
     * @date 2019/12/10 17:07
     */
    private static class GracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {
        private volatile Connector connector;
        private final int waitTime = 180;

        @Override
        public void customize(Connector connector) {
            this.connector = connector;
        }

        /**
         * 应用关闭事件回调函数
         * @author 郭闪
         * @date 2019/12/26
         * @param event 应用关闭事件
         *
         */
        @Override
        public void onApplicationEvent(ContextClosedEvent event) {
            if (null != this.connector) {
                //获取服务发现类，并将服务从eureka下线
                DiscoveryClient discoveryClient = SpringUtil.getBean(DiscoveryClient.class);
                discoveryClient.shutdown();
                logger.info("已将服务状态设为下线，开始睡五秒");
                try {
                    Thread.sleep(5000);
                    logger.info("五秒已过，开始停止服务");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }

                this.connector.pause();
                Executor executor = this.connector.getProtocolHandler().getExecutor();
                if (executor instanceof ThreadPoolExecutor) {
                    try {
                        //获取容器线程池执行器，关闭容器中的线程
                        ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
                        threadPoolExecutor.shutdown();
                        if (!threadPoolExecutor.awaitTermination(waitTime, TimeUnit.SECONDS)) {
                            logger.error("Tomcat thread pool did not shut down gracefully within "
                                            + waitTime + " seconds. Proceeding with forceful shutdown");
                        }
                    } catch (InterruptedException ex) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        }
    }
}

